package com.example.shardingjdbcdemo.config;

import com.google.common.collect.Range;
import org.apache.shardingsphere.infra.util.exception.external.sql.type.generic.UnsupportedSQLOperationException;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;

public class MonthShardingAlgorithm implements StandardShardingAlgorithm<LocalDate> {
    private Properties props;
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
    String tableTemplate = "%s_%s";

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<LocalDate> shardingValue) {
        LocalDate value = shardingValue.getValue();
        String logicTableName = shardingValue.getLogicTableName();
        return String.format(tableTemplate, logicTableName, formatter.format(value));
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<LocalDate> shardingValue) {
        Range<LocalDate> valueRange = shardingValue.getValueRange();
        LocalDate upperValue = valueRange.upperEndpoint();
        LocalDate lowerValue = valueRange.lowerEndpoint();
        if (lowerValue.isAfter(upperValue)) {
            throw new UnsupportedSQLOperationException("upperValue must be after lowerValue");
        }
        String logicTableName = shardingValue.getLogicTableName();
        List<String> result = new ArrayList<>();
        while (lowerValue.isBefore(upperValue)) {
            String realTableName = String.format(tableTemplate, logicTableName, formatter.format(lowerValue));
            result.add(realTableName);
            lowerValue = lowerValue.plusMonths(1);
        }
        return result;
    }

    @Override
    public Properties getProps() {
        return this.props;
    }

    @Override
    public void init(Properties properties) {
        this.props = properties;
    }
}
